package earogya.ehr.patient_details.messages;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.hibernate.HibernateException;

import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.DataTypeException;
import ca.uhn.hl7v2.model.v251.datatype.XCN;
import ca.uhn.hl7v2.model.v251.group.ADR_A19_QUERY_RESPONSE;
import ca.uhn.hl7v2.model.v251.message.ADR_A19;
import ca.uhn.hl7v2.model.v251.message.QRY_A19;
import ca.uhn.hl7v2.model.v251.segment.MSH;
import ca.uhn.hl7v2.model.v251.segment.PID;
import ca.uhn.hl7v2.model.v251.segment.QRD;
import earogya.ehr.patient_details.*;

/***
 * 
 * QRY A19 message is used to query the details of the patients.
 * Reply with a ADR A19 message containing the required details
 * 
 * @author Ureka
 *
 */

public class QRY_A19_Handler {
	private QRY_A19 qryMsg;
	HibernateManager hibernateManager = new HibernateManager();

	public QRY_A19_Handler(QRY_A19 qryMsg) {
		this.qryMsg = qryMsg;
	}

	String ack = null;

	
	/**
	 * 
	 * Identify the segments in the message and get the details from the database
	 * 
	 * @return
	 * @throws HL7Exception
	 * @throws IOException
	 */
	public String manageMessage() throws HL7Exception, IOException {
		try{
		QRD qrd = qryMsg.getQRD();

		if (qrd.getWhatSubjectFilter(0).getIdentifier().getValue()
				.equals("DEM")) {
			ack = this.createPatientDetailsResponseMessage();
		} else {
			HL7Exception ex = new HL7Exception("Invalid query");
			ack = qryMsg.generateACK("AE", ex).encode();
		}
		} catch (HibernateException e) {
			HL7Exception ex = new HL7Exception("Error occured while Database access");
			ack = qryMsg.generateACK("AE", ex).encode();
		} catch (IOException e) {
			HL7Exception ex = new HL7Exception("An IO error ocuured");
			ack = qryMsg.generateACK("AE", ex).encode();
		} catch(DataTypeException e){
			HL7Exception ex = new HL7Exception("An error occured while data type conversion");
			ack = qryMsg.generateACK("AE", ex).encode();
		}catch (HL7Exception e) {
			HL7Exception ex = new HL7Exception("Could not parse the message");
			ack = qryMsg.generateACK("AE", ex).encode();
		}catch(Exception e){
			HL7Exception ex = new HL7Exception("An error occured");
			ack = qryMsg.generateACK("AE", ex).encode();
		}
		return ack;
	}

	
	/**
	 * 
	 * Create the response message containing the required patient details
	 * 
	 * @return
	 * @throws HL7Exception
	 * @throws IOException
	 * @throws HibernateException
	 * @throws DataTypeException
	 */
	public String createPatientDetailsResponseMessage() throws HL7Exception, IOException, HibernateException, DataTypeException {
		String msg = null;
		ADR_A19 ADRA19msg = new ADR_A19();
		QRD qrd = qryMsg.getQRD();
		XCN[] who = qrd.getWhoSubjectFilter();
		String[] requiredFields = { "patientId", "prefix", "givenName",
				"familyName", "nicNo", "gender", "birthTime",
				"birthPlaceAddress", "multipleBirthIndex",
				"multipleBirthOrderNumber", "organDonorIndex",
				"maritialStatus", "educationalLevelId", "livingArrangementId",
				"religiousAffliationId", "ethnicGroupId",
				"confidentialityLevelId", "veryImportantPatientId",
				"deceasedIndex", "deceasedTime" };
		Object[][] fieldsAndValues = {
				{ "patientId", who[0].getIDNumber().getValue() },
				{ "givenName", who[0].getGivenName().getValue() },
				{ "familyName", who[0].getFamilyName().getSurname().getValue()},
				{ "nicNo", who[0].getIdentifierCheckDigit().getValue() } ,
				{ "isActive", '1'}};
		List patientList = new HibernateManager().queryValueListFromDatabase(
				fieldsAndValues, requiredFields, "Patient", "patient");
		MSH mshSegment = ADRA19msg.getMSH();
		mshSegment.getFieldSeparator().setValue("|");
		mshSegment.getEncodingCharacters().setValue("^~\\&");
		mshSegment.getDateTimeOfMessage().getTime()
				.setValue(Calendar.getInstance().getTime());
		mshSegment.getMessageType().getMsg1_MessageCode().setValue("ADR");
		mshSegment.getVersionID().getVersionID().setValue("2.5.1");
		mshSegment.getMessageType().getTriggerEvent().setValue("A19");

		if (patientList.size() > 0) {
			for (int i = 0; i < patientList.size(); i++) {
				Object[] patientDetails = (Object[]) patientList.get(i);
				ADR_A19_QUERY_RESPONSE response = ADRA19msg
						.insertQUERY_RESPONSE(i);
				PID pid = response.getPID();
				pid.getPatientID().getIDNumber()
						.setValue(patientDetails[0].toString());
				if (patientDetails[1] == null) {
				} else {
					pid.getPatientName(0).getPrefixEgDR()
							.setValue(patientDetails[1].toString());
				}
				if (patientDetails[2] == null) {
				} else {
					pid.getPatientName(0).getGivenName()
							.setValue(patientDetails[2].toString());
				}
				if (patientDetails[3] == null) {
				} else {
					pid.getPatientName(0).getFamilyName().getSurname()
							.setValue(patientDetails[3].toString());
				}
				if (patientDetails[4] == null) {
				} else {
					pid.getPatientIdentifierList(0).getIDNumber()
							.setValue(patientDetails[4].toString());
				}
				if (patientDetails[5] == null) {
				} else {
					pid.getAdministrativeSex().setValue(
							patientDetails[5].toString());
				}

				if (patientDetails[6] == null) {
				} else {
					pid.getDateTimeOfBirth().getTime()
							.setValue((Date) patientDetails[6]);
				}
				if (patientDetails[7] == null) {
				} else {
					pid.getBirthPlace().setValue(patientDetails[7].toString());
				}
				if (patientDetails[11] == null) {
				} else {
					pid.getMaritalStatus().getText()
							.setValue(patientDetails[11].toString());
				}
				if (patientDetails[15] == null) {
				} else {
					pid.getEthnicGroup(0).getText()
							.setValue(patientDetails[15].toString());
				}
				if (patientDetails[14] == null) {
				} else {
					pid.getReligion().getText()
							.setValue(patientDetails[14].toString());
				}
				List patientAddressList = this.getPatientAddressDetails(Integer
						.parseInt(patientDetails[0].toString()));
				for (int j = 0; j < patientAddressList.size(); j++) {
					Object[] patientAddress = (Object[]) patientAddressList
							.get(j);
					if (patientAddress[4] == null) {
					} else {
						pid.getPatientAddress(0).getOtherDesignation()
								.setValue(patientAddress[4].toString());
					}
					if (patientAddress[6] == null) {
					} else {
						pid.getPatientAddress(0).getCountry()
								.setValue(patientAddress[6].toString());
					}
					if (patientAddress[2] == null) {
					} else {
						pid.getPatientAddress(0).getStreetAddress()
								.getDwellingNumber()
								.setValue(patientAddress[2].toString());
					}
					if (patientAddress[5] == null) {
					} else {
						pid.getPatientAddress(0).getCity()
								.setValue(patientAddress[5].toString());
					}
					if (patientAddress[3] == null) {
					} else {
						pid.getPatientAddress(0).getStreetAddress()
								.getStreetName()
								.setValue(patientAddress[3].toString());
					}

				}
				List patientEmailList = this.getPatientEmailDetails(Integer
						.parseInt(patientDetails[0].toString()));
				for (int j = 0; j < patientEmailList.size(); j++) {
					Object[] patientEmail = (Object[]) patientEmailList.get(j);
					pid.getPhoneNumberHome(j).getEmailAddress()
							.setValue(patientEmail[2].toString());
				}

				List patientTelephoneList = this
						.getPatientTelephoneDetails(Integer
								.parseInt(patientDetails[0].toString()));
				for (int j = 0; j < patientTelephoneList.size(); j++) {
					Object[] patientTelephone = (Object[]) patientTelephoneList
							.get(j);
					pid.getPhoneNumberHome(j).getTelephoneNumber()
							.setValue(patientTelephone[2].toString());
				}
				msg = ADRA19msg.getMessage().encode();
			}
		} else {
			HL7Exception expection = new HL7Exception(
					"No matching Search Results");
			msg = qryMsg.generateACK("AR", expection).encode();
		}

		return msg;
	}

	
	/**
	 * 
	 * Get the patient's address details from the database
	 * 
	 * @param patientId
	 * @return
	 * @throws IOException
	 * @throws HibernateException
	 * @throws DataTypeException
	 */
	private List getPatientAddressDetails(int patientId) throws IOException, HibernateException, DataTypeException {
		Object[][] fieldsAndValues = { { "patientId", patientId } };
		String[] requiredFields = { "patientAddressId", "patientId",
				"houseNumber", "street", "city1", "city2", "country" };
		List patientAddressList = hibernateManager.queryValueListFromDatabase(
				fieldsAndValues, requiredFields, "PatientAddress",
				"patientAddress");
		return patientAddressList;
	}

	
	/**
	 * 
	 * Get the patient's email details from the database
	 * 
	 * @param patientId
	 * @return
	 * @throws IOException
	 * @throws HibernateException
	 * @throws DataTypeException
	 */
	private List getPatientEmailDetails(int patientId) throws IOException, HibernateException, DataTypeException {
		Object[][] fieldsAndValues = { { "patientId", patientId } };
		String[] requiredFields = { "patientEmailId", "patientId", "email" };
		List patientEmailList = hibernateManager
				.queryValueListFromDatabase(fieldsAndValues, requiredFields,
						"PatientEmail", "patientEmail");
		return patientEmailList;
	}

	
	/**
	 * 
	 * Get the patient's telephone details from the database
	 * 
	 * @param patientId
	 * @return
	 * @throws IOException
	 * @throws HibernateException
	 * @throws DataTypeException
	 */
	private List getPatientTelephoneDetails(int patientId) throws IOException, HibernateException, DataTypeException {
		Object[][] fieldsAndValues = { { "patientId", patientId } };
		String[] requiredFields = { "patientTelephoneNoId", "patientId",
				"telephoneNo" };
		List patientTelephoneList = hibernateManager
				.queryValueListFromDatabase(fieldsAndValues, requiredFields,
						"PatientTelephone", "patientTelephone");
		return patientTelephoneList;
	}

}
